package com.potevio.simulator.util;


import com.potevio.simulator.common.GetHexMessage;
import com.potevio.simulator.common.MsgBean;
import com.potevio.simulator.config.MsgTypeConst;
import com.potevio.simulator.heart.HeartbeatClient;
import com.potevio.simulator.init.ApplicationStartQuartzJobListener;
import com.potevio.simulator.strategy.CommandContext;
import com.potevio.simulator.strategy.MsgFieldTypeStrategy;
import io.netty.channel.Channel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.sf.json.JSONObject;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @Description: 16进制转换工具类
 * @Author: zyd
 * @Date: 2021/5/7
 */
public class HexUtil {
    private static final Logger LOGGER = LoggerFactory.getLogger(HexUtil.class);

    private static final char HexCharArr[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};

    private static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    /**
     * @param str 16进制字符串
     * @return 字节数组
     * @Title:hexString2Bytes
     * @Description:16进制字符串转字节数组
     */
    public static byte[] hexString2Bytes(String str) {
        str = str.replaceAll(" ", "");
        byte[] bytes = new byte[str.length() / 2];
        for (int i = 0; i < str.length() / 2; i++) {
            String subStr = str.substring(i * 2, i * 2 + 2);
            bytes[i] = (byte) Integer.parseInt(subStr, 16);
        }
        return bytes;
    }

    /**
     * 将16进制的byte数组转换成字符串
     *
     * @param raw
     * @return
     */
    public static String getBufHexStr(byte[] raw) {
        String HEXES = "0123456789ABCDEF";
        if (raw == null) {
            return null;
        }
        final StringBuilder hex = new StringBuilder(2 * raw.length);
        for (final byte b : raw) {
            hex.append(HEXES.charAt((b & 0xF0) >> 4))
                    .append(HEXES.charAt((b & 0x0F)));
        }
        return hex.toString();
    }

    /**
     * 字节数组转为16进制字符串
     *
     * @param btArr
     * @return
     */
    public static String byteArrToHex(byte[] btArr) {
        char strArr[] = new char[btArr.length * 2];
        int i = 0;
        for (byte bt : btArr) {
            strArr[i++] = HexCharArr[bt >>> 4 & 0xf];
            strArr[i++] = HexCharArr[bt & 0xf];
        }
        return new String(strArr);
    }

    /**
     * ascii转16进制
     *
     * @param str
     * @return
     */
    public static String ascii2Hex(String str) {
        char[] chars = str.toCharArray();
        StringBuffer hex = new StringBuffer();
        for (int i = 0; i < chars.length; i++) {
            hex.append(Integer.toHexString((int) chars[i]));
        }
        return hex.toString();
    }

    /**
     * 16进制转ascii
     *
     * @param hexStr
     * @return
     */
    public static String hex2Ascii(String hexStr) {
        StringBuilder sb = new StringBuilder();
        StringBuilder temp = new StringBuilder();
        for (int i = 0; i < hexStr.length() - 1; i += 2) {
            String output = hexStr.substring(i, (i + 2));
            int decimal = Integer.parseInt(output, 16);
            sb.append((char) decimal);
            temp.append(decimal);
        }
        return sb.toString();
    }

    /**
     * 数字字符串转16进制
     *
     * @param str
     * @return
     */
    public static String intStr2Hex(String str) {
        StringBuffer stringBuffer = new StringBuffer();
        for (int i = 0; i < str.length(); i++) {
            String tempStr = Integer.toHexString(Integer.valueOf(str.substring(i, i + 1)));
            if (tempStr.length() < 2) {
                tempStr = "0" + tempStr;
            }
            stringBuffer.append(tempStr);
        }
        return stringBuffer.toString().toUpperCase();
    }

    /**
     * 单个数字转16进制
     *
     * @param num
     * @return
     */
    public static String int2Hex(int num) {
        String hexStr = Integer.toHexString(num);
        if (hexStr.length() < 2) {
            hexStr = "0" + hexStr;
        }
        return hexStr;
    }

    /**
     * 16进制转数字
     *
     * @param hexStr
     * @return
     */
    public static String hex2Int(String hexStr) {
        StringBuffer stringBuffer = new StringBuffer();
        for (int i = 0; i < hexStr.length(); i += 2) {
            String tempStr = hexStr.substring(i, i + 2);
            tempStr = String.valueOf(Integer.parseInt(tempStr, 16));
            stringBuffer.append(tempStr);
        }
        return stringBuffer.toString();
    }

//    public static void main(String[] args) {
//        int chargeTime = 16;
//        String ctStr = "";
//        if(chargeTime <= 15 ){
//            ctStr = HexUtil.int2Hex(chargeTime) + "00";
//        }else {
//            ctStr = HexUtil.random2HexAndReverse(chargeTime);
//        }
//        System.out.println(ctStr);
//    }

    /**
     * 时间字符串（yyyy-MM-dd hh:mm:ss）转为16进制
     *
     * @param string
     * @return
     * @throws ParseException
     */
    public static String time2Hex(String string) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        Date date = sdf.parse(string);

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int year = calendar.get(Calendar.YEAR);
        int month = calendar.get(Calendar.MONTH) + 1;
        int day = calendar.get(Calendar.DATE);
        int hour = calendar.get(Calendar.HOUR_OF_DAY);
        int minute = calendar.get(Calendar.MINUTE);
        int second = calendar.get(Calendar.SECOND);
        String yearHex = "0" + Integer.toHexString(year);
        yearHex = yearHex.substring(2, 4) + yearHex.substring(0, 2);
        return yearHex + int2Hex(month) + int2Hex(day) + int2Hex(hour) + int2Hex(minute) + int2Hex(second) + "FF";
    }

    /**
     * 16进制时间转时间字符串（yyyy-MM-dd hh:mm:ss）
     *
     * @param hexStr
     * @return
     */
    public static StringBuffer hex2Time(String hexStr) {
        String year = String.valueOf(Integer.parseInt(hexStr.substring(3, 4) + hexStr.substring(0, 2), 16));
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append(year).append("-");
        for (int i = 4; i < hexStr.length(); i += 2) {
            if (!"FF".equals(hexStr.substring(i, i + 2))) {
                String tempVal = String.valueOf(Integer.parseInt(hexStr.substring(i, i + 2), 16));
                if (tempVal.length() < 2) {
                    tempVal = "0" + tempVal;
                }
                stringBuffer.append(tempVal);
                if (i == 4) {
                    stringBuffer.append("-");
                } else if (i == 6) {
                    stringBuffer.append(" ");
                } else if (i == 8 || i == 10) {
                    stringBuffer.append(":");
                }
            }
        }
        return stringBuffer;
    }

    /**
     * 字符串转16进制-支持中文
     *
     * @param string
     * @return
     */
    public static String gb2Hex(String string) {
        byte[] bt = new byte[0];
        try {
            bt = string.getBytes("GB2312");
        } catch (Exception e) {
            e.printStackTrace();
        }
        String s1 = "";
        for (int i = 0; i < bt.length; i++) {
            String tempStr = Integer.toHexString(bt[i]);
            if (tempStr.length() > 2) {
                tempStr = tempStr.substring(tempStr.length() - 2);
            }
            s1 = s1 + tempStr + "";
        }
        return s1.toUpperCase();
    }

    /**
     * 16进制转字符串-支持中文
     *
     * @param hexStr
     * @return
     */
    public static String hex2GB(String hexStr) {
        byte[] baKeyword = new byte[hexStr.length() / 2];
        for (int i = 0; i < baKeyword.length; i++) {
            try {
                baKeyword[i] = (byte) (0xff & Integer.parseInt(hexStr.substring(
                        i * 2, i * 2 + 2), 16));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        try {
            hexStr = new String(baKeyword, "GB2312");// UTF-16le:Not
        } catch (Exception e1) {
            e1.printStackTrace();
        }
        return hexStr;
    }

    /**
     * 计算校验和域（16进制累加，取最后两位）
     *
     * @param hexdata
     * @return
     */
    public static String getCheckSumDomain(String hexdata) {
        if (hexdata == null || hexdata.equals("")) {
            return "00";
        }
        hexdata = hexdata.replaceAll(" ", "");
        int total = 0;
        int len = hexdata.length();
        if (len % 2 != 0) {
            return "00";
        }
        int num = 0;
        while (num < len) {
            String s = hexdata.substring(num, num + 2);
            total += Integer.parseInt(s, 16);
            num = num + 2;
        }
        String checkSum = Integer.toHexString(total);
        if (checkSum.length() > 2) {
            checkSum = checkSum.substring(checkSum.length() - 2, checkSum.length());
        }
        return checkSum.toUpperCase();
    }

    /**
     * 生成指定范围，指定小数位数的随机数
     *
     * @param max   最大值
     * @param min   最小值
     * @param scale 小数位数
     * @return
     */
    public static BigDecimal makeRandom(float max, float min, int scale) {
        BigDecimal cha = new BigDecimal(Math.random() * (max - min) + min);
        // 保留 scale 位小数，并四舍五入
        return cha.setScale(scale, BigDecimal.ROUND_HALF_UP);
    }

    /**
     * 16进制字符串高低位转换
     *
     * @param hex
     * @return
     */
    public static String reverseHex(String hex) {
        if (hex.length() == 2) {
            if("0".equals(hex.substring(0,1))){
                hex = hex + "00";
            }else {
                hex = "00" + hex;
            }
        } else if (hex.length() == 3) {
            hex = "0" + hex;
        }
        final char[] charArray = hex.toCharArray();
        final int length = charArray.length;
        final int times = length / 2;
        for (int c1i = 0; c1i < times; c1i += 2) {
            final int c2i = c1i + 1;
            final char c1 = charArray[c1i];
            final char c2 = charArray[c2i];
            final int c3i = length - c1i - 2;
            final int c4i = length - c1i - 1;
            charArray[c1i] = charArray[c3i];
            charArray[c2i] = charArray[c4i];
            charArray[c3i] = c1;
            charArray[c4i] = c2;
        }
        return new String(charArray);
    }

    /**
     * 随机数转16进制，高低字节转换
     *
     * @param num
     * @return
     */
    public static String random2HexAndReverse(int num) {
        LOGGER.info("随机数——msgLog：" + num);
        String hexStr = HexUtil.int2Hex(num);
        LOGGER.info("16进制——msgLog：" + hexStr);
        LOGGER.info("高低字节转换后——msgLog：" + HexUtil.reverseHex(hexStr));
        return HexUtil.reverseHex(hexStr);
    }


    /**
     * 格式化报文
     *
     * @param hexStr
     */
    public static StringBuffer addSpace(String hexStr) {
        int num = 0;
        int strl = hexStr.length();
        StringBuffer stringBuffer = new StringBuffer();
        while (num < strl) {
            stringBuffer.append(hexStr.substring(num, num + 2)).append(" ");
            num = num + 2;
        }
        LOGGER.info("格式化报文——msgLog：{}", stringBuffer);
        return stringBuffer;
    }

    /**
     * 将二进制转换成16进制
     *
     * @param bin
     * @return
     */
    public static String bin2Hex(String bin){
        return int2Hex(Integer.parseInt(bin, 2)).toUpperCase();
    }

    /**
     * 计算两个时间十六进制相差时间（秒）
     * @param startTimeHexStr
     * @param endTimeHexStr
     * @return
     * @throws ParseException
     */
    public static String getTimeStrInterval(String startTimeHexStr, Date endTimeHexStr) throws ParseException {
        // 转时间str
        startTimeHexStr = HexUtil.hex2Time(startTimeHexStr).toString();
        int timeInterval = Math.toIntExact(DateUtil.getInterval(endTimeHexStr, SIMPLE_DATE_FORMAT.parse(startTimeHexStr)));
        //时间转换 高低字节判断（转换不同）
        if(timeInterval <= 15 ){
            return HexUtil.int2Hex(timeInterval);
        }else {
            return random2HexAndReverse(timeInterval);
        }

    }
//         getTimeStrInterval 方法备份
//    public static String getTimeStrInterval(String startTimeHexStr, Date endTimeHexStr) throws ParseException {
//        // 转时间str
//        startTimeHexStr = HexUtil.hex2Time(startTimeHexStr).toString();
//        int timeInterval = Math.toIntExact(DateUtil.getInterval(endTimeHexStr, SIMPLE_DATE_FORMAT.parse(startTimeHexStr)));
//
//        return random2HexAndReverse(timeInterval);
//    }

    /**
     * 计算报文字段值长度和实际长度相差字节数
     * @param hexStr
     * @param msgCode
     * @param msgField
     * @return
     */
    public static String getIntervalByteNum(String hexStr, String msgCode, String msgField){
        LinkedHashMap<String, MsgBean> msgBeanMap = ApplicationStartQuartzJobListener.chm.get(msgCode);
        MsgBean msgBean = msgBeanMap.get(msgField);
        // 返回报文的字段值长度
        int revertFieldLength = hexStr.length() / 2;
        // 全局变量中的字段长度
        int msgFieldLength = Integer.valueOf(msgBean.getLength());
        if (revertFieldLength < msgFieldLength) {
            // 计算两个字段长度相差字节数，为了补0
            int num = msgFieldLength - revertFieldLength;
            StringBuffer stringBuffer = new StringBuffer();
            for (int j = 0; j < num * 2; j++) {
                stringBuffer.append("0");
            }
            hexStr = hexStr + stringBuffer;
//            hexStr = HexUtil.reverseHex(hexStr);
        }
        return hexStr;
    }


    public static String int2Bin(int intStr){
        String binStr = Integer.toBinaryString(intStr);
        for (int i = 0; i < 5; i++) {
            if(binStr.length() < i+1){
                binStr = "0" + binStr;
            }
        }
        return binStr;
    }
    /**
     * 解析
     *
     * @param
     * @return
     */
    public static Map<String, LinkedHashMap<String, String>> parse(String hexStrData, String sendOrReceive) throws Exception {
        try{
            // 字节偏移地址
            int num = 4;
            // 取出命令代码
            String commandCode = hexStrData.substring(10, 12);
            if(commandCode.equals("05")){
                System.out.println("0x05------------");
            }
            // 通过命令代码，从全局报文配置变量中取出对应字段的Map集合
            LinkedHashMap<String, MsgBean> msgBeanMap = ApplicationStartQuartzJobListener.chm.get("0x" + commandCode);
            if (msgBeanMap != null) {
                Set<String> keySet = msgBeanMap.keySet();
                Iterator<String> iterator = keySet.iterator();
                LinkedHashMap<String, String> chm = new LinkedHashMap<String, String>();

                // 迭代报文中的每个字段
                while (iterator.hasNext()) {
                    // 字段
                    String key = iterator.next();
                    // 字段对应属性
                    MsgBean msgBean = msgBeanMap.get(key);
                    // 字段长度
                    int size = Integer.valueOf(msgBean.getLength());

                    // 从报文字符串中拆出对应的字节（字节偏移地址，偏移量=本次偏移地址+(当前字段长度*2)）
                    String hexStr = hexStrData.substring(num, num+(size*2));
                    // 字段类型
                    String fieldType = msgBean.getType();
                    // 下次迭代时的偏移地址=本次偏移地址+(当前字段长度*2)
                    num = num + (size * 2);
                    // 用户id和指令序号先不考虑
                    if (!"userId".equals(key) && !"instructionsNumber".equals(key)) {
                        CommandContext commandContext = new CommandContext();
                        MsgFieldTypeStrategy msgFieldTypeStrategy = commandContext.getTypeInstance(fieldType);
                        if(msgFieldTypeStrategy != null){
                            hexStr = msgFieldTypeStrategy.decodeProcess(hexStr);
                        }
                    }
                    chm.put(msgBean.getId(), hexStr);
                    if("gbK".equals(fieldType)){
                        hexStr = hex2GB(hexStr);
                    }
                    LOGGER.info("报文字段——msgLog：{}，名称：{}，值：{}", msgBean.getId(), msgBean.getName(), hexStr);
                }
                Map<String, LinkedHashMap<String, String>> map = new HashMap<>();
                map.put(commandCode, chm);
                // 转为json
                JSONObject jsonObject = JSONObject.fromObject(map);
                LOGGER.info("报文json——msgLog：{}", jsonObject.toString());
                return map;
            }
        }catch (Exception e){
            LOGGER.error("解析异常：{}", e);
        }
        return null;
    }

    /**
     * 发送充电状态为00的34
     * @param channel
     */
    public static void send3400(Channel channel) {
        try{
            // 先发送两条充电状态为00的34报文
            Map<String, LinkedHashMap<String, String>> map34 = new GetHexMessage().getDataDomain(MsgTypeConst.CHARGE_MODEL_STATE_INFO_MSG);
            LinkedHashMap<String, String> chMap = map34.get("0x34");
            map34.put("0x34", chMap);
            for (int i = 0; i < 2; i++) {
                channel.writeAndFlush(map34);
                Thread.sleep(HeartbeatClient.chargeMsgInterval*1000);
            }
        }catch (Exception e){
            LOGGER.error("发送00状态34异常——msgLog：{}", e);
        }
    }

    public static void main(String[] args) throws ParseException {
////        for (int i = 0; i < 10; i++) {
////            String random = String.valueOf((getRandomNumber(1, 3)));
////            System.out.println("随机数：" + random);
////            String hexStr = Integer.toHexString(Integer.valueOf(random));
////            System.out.println("16进制：" + hexStr);
////            System.out.println("高低字节转换后：" + reverseHex("0" + hexStr));
////            System.out.println(getRandomNumber(1,3));
////        }
//
////        System.out.println(intStr2Hex("78"));
////        System.out.println(reverseHex("51"));
////        System.out.println(getRandomDouble(1,3));
////        String ammeterDegreesStr = Integer.toHexString(Integer.valueOf("13786156"));
////            System.out.println(reverseHex(ammeterDegreesStr));
//
////        System.out.println(gb2Hex("去玩儿他范德萨"));
////        System.out.println(hex2GB("D3C3BBA7C3DCC2EBB2BBD5FDC8B72020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020"));
////            System.out.println("Radnom value="+Math.random());
////            System.out.println("Math.abs(-2)="+Math.abs(-2)); //Math.abs()是退回数值的正数
////        getRandomDouble(0,1);
////        for (int i = 0; i <= 10; i++) {
////            BigDecimal bigDecimal = makeRandom(3f, 1f, 2);
////            if(bigDecimal.multiply(new BigDecimal(1000)).intValue() >= 2000){
////                System.out.println(bigDecimal.multiply(new BigDecimal(1000)).intValue());
////            }
////            System.out.println("十进制：" + bigDecimal.toString());
////            System.out.println("十六进制：" + int2Hex(bigDecimal.intValue()));
////            System.out.println("");
////        }
////        String bin = "00000101";
////        System.out.println("16进制为：" + int2Hex(Integer.parseInt(bin, 2)).toUpperCase());
////        System.out.println(getTimeStrInterval("E507060A0E2D0AFF", new Date()));
//        String hex = "34 00 00 00 00 02 05 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 0C 00 00 00 00 01 09 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 0C 00 00 00 00 03";
        String hex = "3A0000000002050100000000000000000000800C0000000032320000000000000000010001090100000000000000000000800C0000000032320000000000000000010001";
        System.out.println(getCheckSumDomain(hex));
        int num = 99;
        String hexStr = HexUtil.int2Hex(num);
        System.out.println("sss="+HexUtil.hex2Int("00A5"));
        System.out.println("hhh="+hexStr);

    }


}
